package com.panda.cn.config.permission;


import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Editor;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.panda.cn.component.SpringBeanUtil;
import com.panda.cn.config.exception.CustomException;
import com.panda.cn.entity.platform.PlAppEntity;
import com.panda.cn.entity.platform.PlAppKeyEntity;
import com.panda.cn.entity.platform.PlInterfaceEntity;
import com.panda.cn.mapper.platform.PlAppKeyMapper;
import com.panda.cn.mapper.platform.PlAppMapper;
import com.panda.cn.mapper.platform.PlInterfaceMapper;

import java.util.Arrays;
import java.util.Date;

/**
 * @Author:Mr.Yan
 * @Description: token 创建 验证 解密
 */
public class PermissionUtil {
    
    private final static PlAppKeyMapper plAppKeyMapper = SpringBeanUtil.getBean(PlAppKeyMapper.class);
    private final static PlAppMapper plAppMapper = SpringBeanUtil.getBean(PlAppMapper.class);
    private final static PlInterfaceMapper plInterfaceMapper = SpringBeanUtil.getBean(PlInterfaceMapper.class);
    
    public static void verify(String key, String uri, String ip) {
        if (StrUtil.isBlank(key)) {
            throw new CustomException("缺少参数key");
        }
        // 判读接口是否存在在接口表中
        LambdaQueryWrapper<PlInterfaceEntity> interfaceQueryWrapper = new LambdaQueryWrapper<>();
        interfaceQueryWrapper.eq(PlInterfaceEntity::getUri, uri)
                .eq(PlInterfaceEntity::getIsDelete, "N");
        Integer interfaceCount = plInterfaceMapper.selectCount(interfaceQueryWrapper);
        if (interfaceCount <= 0) {
            throw new CustomException("未找到当前调用的接口地址");
        }
        
        // 查看key是否有效 是否未删除
        LambdaQueryWrapper<PlAppKeyEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PlAppKeyEntity::getCode, key)
                .eq(PlAppKeyEntity::getIsDelete, "N");
        
        // 查询是存在
        PlAppKeyEntity plAppKeyEntity = plAppKeyMapper.selectOne(queryWrapper);
        
        // 不存在返回
        if (ObjUtil.isEmpty(plAppKeyEntity)) {
            throw new CustomException(StrUtil.format("[{}]未找到相关Key", key));
        }
        
        // 已失效返回
        if (!"Y".equals(plAppKeyEntity.getIsValid())) {
            throw new CustomException(StrUtil.format("[{}]当前Key已失效,请联系管理员", key));
        }
    
        String whiteIp = plAppKeyEntity.getWhiteIp();
        // 验证白名单
        if(!verifyIp(whiteIp, ip))
            throw new CustomException(StrUtil.format("[{}]当前Key限制IP[{}]访问，请联系管理员", key, ip));
        
        // 判断key的时间是否有效 是否>开始时间 <结束时间
        Date startTime = plAppKeyEntity.getStartTime();
        Date endTime = plAppKeyEntity.getEndTime();
        // 当前时间
        Date date = DateUtil.parse(DateUtil.now(), "yyyy-MM-dd");
        // 当前时间>开始时间 返回
        if (date.compareTo(startTime) < 0) {
            throw new CustomException(StrUtil.format("[{}]当前Key未到指定日期范围使用，请联系管理员", key));
        }
        // 当前时间>结束时间 返回
        if (date.compareTo(endTime) > 0) {
            throw new CustomException(StrUtil.format("[{}]当前Key已超过指定日期范围使用，请联系管理员", key));
        }
        
        // 判断其应用是否删除
        LambdaQueryWrapper<PlAppEntity> appQueryWrapper = new LambdaQueryWrapper<>();
        appQueryWrapper.eq(PlAppEntity::getCode, plAppKeyEntity.getAppCode())
                .eq(PlAppEntity::getIsDelete, "N");
        Integer count = plAppMapper.selectCount(appQueryWrapper);
        // 不存在应用返回
        if (count <= 0) {
            throw new CustomException(StrUtil.format("[{}]当前Key所在应用已删除,请更换有效应用Key", key));
        }
        
        // 判断Key是否绑定了接口的权限
        JSONObject keyUriParams = new JSONObject();
        keyUriParams.set("key", key);
        keyUriParams.set("uri", uri);
        Integer havaInterface = plInterfaceMapper.findInterCountByKeyAndUri(keyUriParams);
        if (havaInterface <= 0) {
            throw new CustomException(StrUtil.format("[{}]当前Key没有调用此接口权限,请联系管理员", key));
        }
        
        // 判断其调用次数是否超过限制
        if (plAppKeyEntity.getCallCount() >= plAppKeyEntity.getSumCount()) {
            throw new CustomException(StrUtil.format("[{}]当前Key调用次数达到上限,请联系管理员", key));
        }
        
        // 将调用次数添加1
        PlAppKeyEntity params = new PlAppKeyEntity();
        params.setId(plAppKeyEntity.getId());
        params.setCallCount(plAppKeyEntity.getCallCount() + 1);
        // 当前时间
        DateTime nowDateTime = DateUtil.parse(DateUtil.now());
        params.setUpdateTime(nowDateTime);
        plAppKeyMapper.updateById(params);
    }
    
    
    /**
     * 验证ip
     *
     * @param whiteIp 白色ip
     * @param ip      知识产权
     * @return boolean
     */
    private static boolean verifyIp(String whiteIp, String ip){
        // 限制ip名单
        if (StrUtil.isNotBlank(whiteIp) && !"*".equals(whiteIp)) { // 存在白名单 不为空和*
            // 白名单列表
            String[] whiteIpArr = whiteIp.split(",");
            // 用于判断是否存在白名单中 false 代表不存在
            boolean flag = false;
            //  判断是不是存在 循环白名单
            for (int i = 0; i < whiteIpArr.length; i++) {
                String wIp = whiteIpArr[i];
                // 验证是否存在 *
                if ("*".equals(wIp)) {
                    flag = true;
                    break;
                }
                // 判断存在星号
                if(wIp.contains("*")) {
                    // 分割Ip直至没有星为止
                    String[] wIpArr = wIp.split("\\.");
                    String[] ipArr = ip.split("\\.");
                    // 利用等效替换法替换*
                    for (int j = 0; j < wIpArr.length; j++) {
                        // 找到星
                        if("*".equals(wIpArr[j])){
                            wIpArr[j] = ipArr[j];
                        }
                    }
                
                    // 验证ip和白名单一致 跳出验证
                    if (StrUtil.join( ".", wIpArr).equals(StrUtil.join(".", ipArr))) {
                        flag = true;
                        break;
                    }
                } else { // 不存在星号
                    // 验证ip和白名单一致 跳出验证
                    if (ip.equals(wIp)) {
                        flag = true;
                        break;
                    }
                }
            }
            return flag;
        }
        
        return true;
    }
}
